---
title: Business rules
summary: Rules enforced (or declared but not enforced) during UC4 job-invocation message processing.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-09-22
---

# Business rules

Thirteen rules govern job-invocation processing in this host. Two ([BR-UC4-007](#br-uc4-007-job-and-parameter-names-must-not-contain-spaces-declared-not-enforced)) are declared in code but never reached by any caller path, and are recorded as findings rather than silently omitted. No rule in this catalog is enforced by an inherited base class: `UC4Service` derives from no base class, and the applied `[LogErrorBehavior]` service behavior contributes logging, not rule enforcement. [BR-UC4-004](#br-uc4-004-job-name-must-not-be-null) is the only rule whose mechanism lives in a dependency package.

## BR-UC4-001 job allowed by uc4 rules document

| Field | Value |
| --- | --- |
| **Statement** | A job may run only if the `uc4.rules` allow/deny document, evaluated for the requested environment, permits it. |
| **Trigger** | Any job-execution operation |
| **Enforcement** | service |
| **Origin** | `UC4Service.IsJobAllowed` (`src/WCF/SAIF.Services.WCF.UC4.Host/UC4Service.cs:51-129`) |
| **Reached from** | [`ExecuteJob`](operations/execute-job.md), [`ExecuteJobWithClientId`](operations/execute-job-with-client-id.md), [`ExecuteJobWithJson`](operations/execute-job-with-json.md), [`ExecuteJobWithJsonAndClientId`](operations/execute-job-with-json-and-client-id.md), [`ExecuteJobWithValues`](operations/execute-job-with-values.md), [`ExecuteJobWithValuesAndClientId`](operations/execute-job-with-values-and-client-id.md), [`ExecuteJobWithParameters`](operations/execute-job-with-parameters.md), [`ExecuteJobWithParametersAndClientId`](operations/execute-job-with-parameters-and-client-id.md) |
| **Outcome** | Blocked → default-constructed `UC4Result` (all fields at default); allowed → the downstream result. Mechanism: `if (!IsJobAllowed(environment, jobName, out message)) return new UC4Result();` The `uc4.rules` document is read from the Environment API on every invocation rather than cached, adding avoidable latency and Environment API load to every operation — see [Tech debt](tech-debt.md). |
| **Source** | `src/WCF/SAIF.Services.WCF.UC4.Host/UC4Service.cs` |

## BR-UC4-002 default allow for unmatched environment

| Field | Value |
| --- | --- |
| **Statement** | When the rule document contains no entry for the requested environment, all jobs are allowed — except environment `100`, where all jobs are blocked. |
| **Trigger** | Rule lookup finds no matching `ClientId` |
| **Enforcement** | service |
| **Origin** | `UC4Service.IsJobAllowed` (`UC4Service.cs:64-77`) |
| **Reached from** | All eight operations (via [BR-UC4-001](#br-uc4-001-job-allowed-by-uc4-rules-document)) |
| **Outcome** | Allowed or blocked per [BR-UC4-001](#br-uc4-001-job-allowed-by-uc4-rules-document); the explanatory message is computed and then discarded. This is also security finding F-SEC-003 — see [Tech debt](tech-debt.md). |
| **Source** | `src/WCF/SAIF.Services.WCF.UC4.Host/UC4Service.cs` |

## BR-UC4-003 rule evaluation order and match type

| Field | Value |
| --- | --- |
| **Statement** | Within a matched environment, `AllowByDefault` sets the baseline and the first matching rule flips it; a rule matches by case-insensitive regex when `Type` is `regex`, otherwise by case-insensitive literal equality. |
| **Trigger** | Rule set found for the requested environment |
| **Enforcement** | service |
| **Origin** | `UC4Service.IsJobAllowed` (`UC4Service.cs:80-106`) |
| **Reached from** | All eight operations (via [BR-UC4-001](#br-uc4-001-job-allowed-by-uc4-rules-document)) |
| **Outcome** | Determines allow/block per [BR-UC4-001](#br-uc4-001-job-allowed-by-uc4-rules-document). An invalid regex in the rule document throws, surfaced as a WCF default fault.* |
| **Source** | `src/WCF/SAIF.Services.WCF.UC4.Host/UC4Service.cs` |

## BR-UC4-004 job name must not be null

| Field | Value |
| --- | --- |
| **Statement** | `jobName` must not be null. |
| **Trigger** | Entry to `ExecuteJobWithJsonAndClientId`, `ExecuteJobWithValuesAndClientId`, or `ExecuteJobWithParametersAndClientId` |
| **Enforcement** | inherited* |
| **Origin** | `SAIF.Services.Utilities.Enforce.ArgumentNotNull(jobName, "jobName")` (`SAIF.Framework.Core`), called at `UC4Service.cs:162, 189, 209` |
| **Reached from** | [`ExecuteJobWithJsonAndClientId`](operations/execute-job-with-json-and-client-id.md), [`ExecuteJobWithValuesAndClientId`](operations/execute-job-with-values-and-client-id.md), [`ExecuteJobWithParametersAndClientId`](operations/execute-job-with-parameters-and-client-id.md), and the four obsolete forms that delegate to them |
| **Outcome** | Exception from the framework guard, surfaced as a WCF default fault carrying exception detail (`includeExceptionDetailInFaults="true"`) |
| **Source** | `src/WCF/SAIF.Services.WCF.UC4.Host/UC4Service.cs` |

## BR-UC4-005 blocked job returns empty result with no explanation

| Field | Value |
| --- | --- |
| **Statement** | A blocked job returns an empty result and no explanation; the diagnostic message computed by the rule evaluation is never returned to the caller. |
| **Trigger** | Rule evaluation returns `false` |
| **Enforcement** | service |
| **Origin** | `UC4Service.cs:168-171, 191-194, 211-214` |
| **Reached from** | All eight operations |
| **Outcome** | Caller receives `new UC4Result()` and cannot distinguish "blocked" from "downstream returned nothing". Tech-debt finding — see [Tech debt](tech-debt.md). |
| **Source** | `src/WCF/SAIF.Services.WCF.UC4.Host/UC4Service.cs` |

## BR-UC4-006 enum operation forms are obsolete

| Field | Value |
| --- | --- |
| **Statement** | The four `UC4Environment`-typed operation forms are deprecated in favour of the `short` client-id forms. |
| **Trigger** | Compile-time/consumer guidance |
| **Enforcement** | service |
| **Origin** | `[Obsolete("The Enums for Enviroments is not kept up to date, please use method that takes in number for clientID")]` (`UC4Service.cs:138, 151, 179, 199`) |
| **Reached from** | [`ExecuteJob`](operations/execute-job.md), [`ExecuteJobWithJson`](operations/execute-job-with-json.md), [`ExecuteJobWithValues`](operations/execute-job-with-values.md), [`ExecuteJobWithParameters`](operations/execute-job-with-parameters.md) |
| **Outcome** | No runtime effect; the operations remain public and callable, and each delegates to its corresponding `AndClientId` operation after converting the enum with `UC4EnvironmentFactory.GetUC4ClientId(environment)` |
| **Source** | `src/WCF/SAIF.Services.WCF.UC4.Host/UC4Service.cs` |

## BR-UC4-007 job and parameter names must not contain spaces declared not enforced

| Field | Value |
| --- | --- |
| **Statement** | *(Declared, not enforced)* A job name must not contain a space, and no parameter name may contain a space. |
| **Trigger** | Would be entry validation on every job-execution operation |
| **Enforcement** | service — **declared but never enforced**: `UC4Service.Validate` (`UC4Service.cs:239-256`) has no caller anywhere in this host |
| **Origin** | `UC4Service.Validate` (`UC4Service.cs:239`) |
| **Reached from** | None — no operation calls this method |
| **Outcome** | None. `ERR_JOB_NAME_INVALID` (-101) and `ERR_PARAMETER_NAME_INVALID` (-102) are never produced by any code path. Recorded so the gap between declared intent and actual behavior is visible — see [Tech debt](tech-debt.md). |
| **Source** | `src/WCF/SAIF.Services.WCF.UC4.Host/UC4Service.cs` |

## BR-UC4-008 every invocation is traced at INFO

| Field | Value |
| --- | --- |
| **Statement** | Every operation invocation is traced at threshold `INFO` with the invoked method name and the job name. |
| **Trigger** | Entry to every operation |
| **Enforcement** | service (delegating to inherited logging*) |
| **Origin** | `UC4Service.Logging` (`UC4Service.cs:259-262`), called first in each operation, via `SAIF.Core.Services.LogService` |
| **Reached from** | All eight operations |
| **Outcome** | No caller-visible effect; a trace record is written through `LogService` |
| **Source** | `src/WCF/SAIF.Services.WCF.UC4.Host/UC4Service.cs` |

## BR-UC4-009 positional values are named arg1 arg2

| Field | Value |
| --- | --- |
| **Statement** | Positional values are named `arg1`, `arg2`, and each subsequent positional argument name in call order before being forwarded. |
| **Trigger** | `values`-form operations |
| **Enforcement** | service |
| **Origin** | `UC4Service.GetParameters` (`UC4Service.cs:227-235`) |
| **Reached from** | [`ExecuteJobWithClientId`](operations/execute-job-with-client-id.md), [`ExecuteJobWithValuesAndClientId`](operations/execute-job-with-values-and-client-id.md), [`ExecuteJob`](operations/execute-job.md), [`ExecuteJobWithValues`](operations/execute-job-with-values.md) |
| **Outcome** | Determines the parameter names the downstream job receives |
| **Source** | `src/WCF/SAIF.Services.WCF.UC4.Host/UC4Service.cs` |

## BR-UC4-010 downstream service address resolved per call

| Field | Value |
| --- | --- |
| **Statement** | The downstream service address is resolved per call from the environment settings `uc4coreapi.url` and `uc4coreapi.schedulejobroute`. |
| **Trigger** | `UC4Client` construction |
| **Enforcement** | service |
| **Origin** | `Uc4Client.cs:24-25`, key names composed in `src/WCF/SAIF.Services.WCF.UC4.Host/EnvironmentConstants.cs` |
| **Reached from** | All eight operations |
| **Outcome** | A missing setting throws, surfaced as a WCF default fault. `ScheduleJobEndpoint` is resolved and never used — tech-debt finding. |
| **Source** | `src/WCF/SAIF.Services.WCF.UC4.Host/Uc4Client.cs` |

## BR-UC4-011 forwarded job stamped with host identity

| Field | Value |
| --- | --- |
| **Statement** | Every forwarded job is stamped with the host's machine name and process user, and with the fixed application id `wcf_uc4`. |
| **Trigger** | `UC4Client` construction |
| **Enforcement** | service |
| **Origin** | `Uc4Client.cs:26-31`; `APP_NAME` at `UC4Service.cs:26` |
| **Reached from** | All eight operations |
| **Outcome** | Downstream audit attributes the job to the service account, not to the caller. This is also security finding F-SEC-006 — see [Tech debt](tech-debt.md). |
| **Source** | `src/WCF/SAIF.Services.WCF.UC4.Host/Uc4Client.cs` |

## BR-UC4-012 downstream result mapped field by field

| Field | Value |
| --- | --- |
| **Statement** | The downstream result is mapped field-by-field onto the published contract type — `Success`, `Error`, `Details`, `Parameters`, `AccessDenied`, `ClientId`, `Message`, `Code`, `JobName`, `RunId`. |
| **Trigger** | Downstream call returns |
| **Enforcement** | service |
| **Origin** | `UC4Client.ConvertFromClientToCoreContractForUC4Results` (`Uc4Client.cs:55-74`) |
| **Reached from** | All eight operations |
| **Outcome** | The caller's `UC4Result` carries exactly these ten values; any field the downstream type adds is silently dropped |
| **Source** | `src/WCF/SAIF.Services.WCF.UC4.Host/Uc4Client.cs` |

## BR-UC4-013 JSON parameters parsed before the allow deny gate

| Field | Value |
| --- | --- |
| **Statement** | The JSON forms accept the caller's parameters as a serialized `KeyValuePair<string,string>[]`, parsed before the allow/deny gate. |
| **Trigger** | JSON-form operations |
| **Enforcement** | service |
| **Origin** | `JsonConvert.DeserializeObject` (`UC4Service.cs:165-166`) |
| **Reached from** | [`ExecuteJobWithJsonAndClientId`](operations/execute-job-with-json-and-client-id.md), [`ExecuteJobWithJson`](operations/execute-job-with-json.md) |
| **Outcome** | Malformed JSON throws and faults even for a job that the rule set would have blocked |
| **Source** | `src/WCF/SAIF.Services.WCF.UC4.Host/UC4Service.cs` |

## Related documentation
- [Index](index.md)
- [Overview](overview.md)
- [Architecture](architecture.md)
- [Activation and hosting](activation-hosting.md)
- [Operations](operations.md)
- [Faults and error pipeline](faults.md)
- [Authentication and authorization](authentication-authorization.md)
- [Dependencies](dependencies.md)
- [Configuration](configuration.md)
- [Operations and processes](operations-processes.md)
- [Operational runbook](operational-runbook.md)
- [Tech debt](tech-debt.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming
> conventions, or contextual evidence where direct confirmation was not available
> in source artifacts.

## Sources
- `src/WCF/SAIF.Services.WCF.UC4.Host/UC4Service.cs`
- `src/WCF/SAIF.Services.WCF.UC4.Host/Uc4Client.cs`
- `src/WCF/SAIF.Services.WCF.UC4.Host/UC4JobRules.cs`
- `src/WCF/SAIF.Services.WCF.UC4.Host/EnvironmentConstants.cs`
